/*
 * Reksio - Memory Map Editor
 * Copyright (C) 2023 CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In applying this licence, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an Intergovernmental Organization or
 * submit itself to any jurisdiction.
 */

#ifndef ATTRIBUTECONTAINERVALIDATOR_H
#define ATTRIBUTECONTAINERVALIDATOR_H
#include <memory>
#include <vector>
#include "attributevalidator.h"


struct INodeRuleValidator; // fwd decl
class ValidatorNode; // fwd decl
class AttributeValidator; // fwd decl
class AttributeContainer; // fwd decl

class AttributeContainerValidator
{
public:
    explicit AttributeContainerValidator(const std::string& name);
    AttributeContainerValidator(const AttributeContainerValidator& rhs) = delete;
    AttributeContainerValidator& operator=(const AttributeContainerValidator& rhs) = delete;
    AttributeContainerValidator& operator=(AttributeContainerValidator&& rhs);
    AttributeContainerValidator(AttributeContainerValidator&& rhs);
    // add
    void addContainer(std::unique_ptr<AttributeContainerValidator> containerValidator);
    AttributeContainerValidator* addContainer(const std::string& name);
    void addAttribute(const std::string& name, std::vector<std::unique_ptr<INodeRuleValidator>>&& attribute_validators);
    void addAttribute(std::unique_ptr<AttributeValidator> attribute);
    // get
    AttributeValidator* getAttributeValidator(const std::string& name) const;
    AttributeContainerValidator* getContainerValidator(const std::string& name) const;
    std::vector<AttributeValidator*> getAllAttributes() const;
    bool validate(const AttributeContainer* attribute_container, const bool recursive = true);
    bool isValid(const AttributeContainer* attribute_container, const bool recursive = true) const;
    std::vector<AttributeValidator*> missingAttributes(const AttributeContainer* attribute_container) const;
    std::vector<AttributeValidator*> requiredAttributes() const;


    const std::vector<std::unique_ptr<AttributeContainerValidator>>& getAttributeContainers() const;
    const std::vector<std::unique_ptr<AttributeValidator>>& getAttributes() const;
    // misc.
    int getTotalSize() const;
    std::vector<std::string> getAllAttributesNames(std::string container_name = "") const;
    const std::string& getName() const;
    std::vector<std::string> getFullName() const;
    ValidatorNode* getParentValidator() const;
    ValidatorNode* getRootParentValidator() const;
    void setParent(ValidatorNode* validator);
    void setParent(AttributeContainerValidator* container);
    AttributeContainerValidator* getParentContainer() const;
    bool isRoot() const;

    bool isAddable() const;
    void setAddable(bool addable);
    bool isRemovable() const;
    void setRemovable(bool removable);
    bool isDeprecated() const;
    void setDeprecated(bool deprecated);
    const std::string& getDeprecatedMessage() const;
    void setDeprecatedMessage(const std::string& msg);

protected:
    void updateParent();
    std::vector<std::unique_ptr<AttributeContainerValidator>> containers;
    std::vector<std::unique_ptr<AttributeValidator>> attributes;
    std::string _name;
    bool _addable = true; // if item can be added by the user
    bool _removable = true; // if item can be removed
    bool _deprecated = false; // if item is deprecated
    std::string _deprecated_msg; // reason of deprecation
    ValidatorNode* _parentNode = nullptr;
    AttributeContainerValidator* _parentContainer = nullptr;
};

#endif // ATTRIBUTECONTAINERVALIDATOR_H
